package com.fengyun.elasticsearch.api;

import org.apache.http.HttpHost;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ESClient {

    private RestHighLevelClient client;

    /**
     * 获取es客户端
     */
    @Before
    public void setClient() {
        if (client == null) {
            client = new RestHighLevelClient(
                    RestClient.builder(new HttpHost("localhost", 9200, "http")));
        }
    }

    /**
     * 关闭es客户端
     */
    @After
    public void close() {
        if (client != null) {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 查询索引
     *
     * @throws IOException
     */
    @Test
    public void queryIndex() throws IOException {
        // 查询索引 - 请求对象
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("user");

        // 发送请求，获取响应
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(response);
        client.close();
    }

    /**
     * 添加文档数据
     *
     * @throws IOException
     */
    @Test
    public void createDoc() throws IOException {
        // 文档数据
        Map<String, Object> map = new HashMap<>();
        map.put("name", "小明");
        map.put("sex", "女");
        map.put("tel", 22);
        // 索引数据，index：索引，id：数据id，source：数据源
        IndexRequest request = new IndexRequest().index("user").id("3").source(map);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * 修改文档数据
     *
     * @throws IOException
     */
    @Test
    public void updateDoc() throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("age", 33);
        UpdateRequest request = new UpdateRequest().index("user").id("3").doc(map);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * 删除文档数据
     */
    @Test
    public void deleteDoc() throws IOException {
        DeleteRequest request = new DeleteRequest().index("user").id("1");
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * <p>全文检索 -- searchSourceBuilder.query(QueryBuilders.matchAllQuery());
     * <p> GET user/_search
     * <p>
     * <p>  {
     * <p>    query:{
     * <p>        match_all:{
     * <p>
     * <p>        }
     * <p>     }
     * <p>  }
     * <p>
     *
     * @throws IOException
     */
    @Test
    public void matchAll() throws IOException {

        SearchRequest request = new SearchRequest();
        request.indices("user");

        // 查询条件构建
        //    QueryBuilders.matchAllQuery() 全文检索（查询所有）
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchAllQuery());

        // 将查询构造器赋值给request
        request.source(searchSourceBuilder);

        // 执行条件查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * 复合查询 -- 所有条件都满足（must）
     * <p>
     * <p> GET user/_search
     * <p>{
     * <p>  "query":{
     * <p>      "bool":{  #
     * <p>       "must":[  # 必须有这些字段
     * <p>         {"match":{"name":"小米"}},
     * <p>         {"match":{"sex":"女"}}
     * <p>        ]
     * <p>      }
     * <p>   }
     * <p>}
     */
    @Test
    public void matchByCondition() throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices("user");

        // 查询条件构造器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(
                        QueryBuilders.boolQuery()
                                .must(QueryBuilders.matchQuery("name", "小米"))
                                .must(QueryBuilders.matchQuery("sex", "女"))
                );

        // 将查询构造器赋值给request
        request.source(searchSourceBuilder);

        // 执行条件查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * 复合查询--满足任意一个条件（should）
     * <p> GET user/_search
     * <p>
     * <p>    {
     * <p>     query:{
     * <p>         bool:{
     * <p>             should:[
     * <p>                 {"match":{"name":"小米"}},
     * <p>                 {"match":{"sex":"女"}}
     * <p>             ]
     * <p>         }
     * <p>     }
     * <p> }
     *
     * @throws IOException
     */
    @Test
    public void shouldByCondition() throws IOException {

        SearchRequest request = new SearchRequest();
        request.indices("user");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(
                        QueryBuilders.boolQuery()
                                .should(QueryBuilders.matchQuery("name", "小米"))
                                .should(QueryBuilders.matchQuery("sex", "女"))
                );
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    /**
     * 范围查询
     *
     * <p>GET user/_search
     * <p>{
     * <p>    query:{
     * <p>        "bool":{
     * <p>            filter:{
     * <p>                range:{
     * <p>                    "age":{
     * <p>                        gt: 20,
     * <p>                        lt: 30
     * <p>                   }
     * <p>                }
     * <p>           }
     * <p>        }
     * <p>    }
     * <p>}
     */
    @Test
    public void searchRange() throws IOException {

        SearchRequest request = new SearchRequest()
                .indices("user");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(
                        QueryBuilders.boolQuery()
                                .filter(
                                        QueryBuilders.rangeQuery("age")
                                                .gt(20)
                                                .lt(30)
                                )
                );
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);

    }

    /**
     * 全文检索，高亮显示
     * <p>
     * <p>GET user/_search
     * <p>{
     * <p>	"query":{
     * <p>		"match":{
     * <p> 			"name" : "小"
     * <p>             }
     * <p>     },
     * <p>    "highlight":{ 
     * <p>         "fields":{
     * <p>             "name":{}
     * <p>        },
     * <p>         "pre_tags" : ["<span style='color: red'>"],
     * <p>         "post_tags" :["</span>"]
     * <p>     }
     * <p>}
     */
    @Test
    public void searchHighLight() throws IOException {

        SearchRequest request = new SearchRequest()
                .indices("user");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchQuery("name", "小"))
                .highlighter(new HighlightBuilder()
                        .field("name")
                        .preTags("<span style=\"color:red\">")
                        .postTags("</span>")
                );
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }


    /**
     * 聚合查询---- 根据人员性别分组，并求出每组的平均年龄
     *
     * <p>
     * <p>GET user/_search
     * <p>{
     * <p>   "query": {
     * <p>     "match_all": {}
     * <p>   },
     * <p>   "aggs": {
     * <p>     "sexTerms": {
     * <p>       "terms": {
     * <p>         "field": "sex",
     * <p>         "size": 100
     * <p>       },
     * <p>       "aggs": {
     * <p>         "ageAvg": {
     * <p>           "avg": {
     * <p>             "field": "age"
     * <p>           }
     * <p>         }
     * <p>       }
     * <p>     }
     * <p>   },
     * <p>   "size": 0
     * <p> }
     *
     * @throws IOException
     */
    @Test
    public void searchAggs() throws IOException {
        SearchRequest request = new SearchRequest()
                .indices("user");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchAllQuery())
                // 聚合查询
                .aggregation(
                        // 根据sex进行分组
                        AggregationBuilders.terms("sexTerms")
                                .field("sex")
                                // 嵌套子集合查询
                                .subAggregation(
                                        // 对年龄求平均值
                                        AggregationBuilders.avg("ageAvg")
                                                .field("age")
                                )
                )
                // size(0)不显示hits命中的数据。（只展示聚合查询的结果）
                .size(0);
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }
    
}
